/**
* This file is part of ORB-SLAM2.
*
* Copyright (C) 2014-2016 Raúl Mur-Artal <raulmur at unizar dot es> (University of Zaragoza)
* For more information see <https://github.com/raulmur/ORB_SLAM2>
*
* ORB-SLAM2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ORB-SLAM2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ORB-SLAM2. If not, see <http://www.gnu.org/licenses/>.
*/

#include "MapPoint.h"
#include "ORBmatcher.h"

#include<mutex>
#include <include/MongoTypes.h>

namespace ORB_SLAM2
{

long unsigned int MapPoint::nNextId=0;
mutex MapPoint::mGlobalMutex;

MapPoint::MapPoint(const cv::Mat &Pos, KeyFrame *pRefKF, Map* pMap):
    mnFirstKFid(pRefKF->mnId), mnFirstFrame(pRefKF->mnFrameId), mnTrackReferenceForFrame(0),
    mnLastFrameSeen(0), mnBALocalForKF(0), mnFuseCandidateForKF(0), mnLoopPointForKF(0), mnCorrectedByKF(0),
    mnCorrectedReference(0), mnBAGlobalForKF(0), nObs(0), mpRefKF(pRefKF), mnVisible(1), mnFound(1), mbBad(false),
    mpReplaced(static_cast<MapPoint*>(NULL)), mfMinDistance(0), mfMaxDistance(0), mpMap(pMap)
{
    Pos.copyTo(mWorldPos);
    mNormalVector = cv::Mat::zeros(3,1,CV_32F);

    // MapPoints can be created from Tracking and Local Mapping. This mutex avoid conflicts with id.
    unique_lock<mutex> lock(mpMap->mMutexPointCreation);
    mnId=nNextId++;
}

MapPoint::MapPoint(const cv::Mat &Pos, Map* pMap, Frame* pFrame, const int &idxF):
    mnFirstKFid(-1), mnFirstFrame(pFrame->mnId), mnTrackReferenceForFrame(0), mnLastFrameSeen(0),
    mnBALocalForKF(0), mnFuseCandidateForKF(0),mnLoopPointForKF(0), mnCorrectedByKF(0),
    mnCorrectedReference(0), mnBAGlobalForKF(0), nObs(0), mpRefKF(static_cast<KeyFrame*>(NULL)), mnVisible(1),
    mnFound(1), mbBad(false), mpReplaced(NULL), mpMap(pMap)
{
    Pos.copyTo(mWorldPos);
    cv::Mat Ow = pFrame->GetCameraCenter();
    mNormalVector = mWorldPos - Ow;
    mNormalVector = mNormalVector/cv::norm(mNormalVector);

    cv::Mat PC = Pos - Ow;
    const float dist = cv::norm(PC);
    const int level = pFrame->mvKeysUn[idxF].octave;
    const float levelScaleFactor =  pFrame->mvScaleFactors[level];
    const int nLevels = pFrame->mnScaleLevels;

    mfMaxDistance = dist*levelScaleFactor;
    mfMinDistance = mfMaxDistance/pFrame->mvScaleFactors[nLevels-1];

    pFrame->mDescriptors.row(idxF).copyTo(mDescriptor);

    // MapPoints can be created from Tracking and Local Mapping. This mutex avoid conflicts with id.
    unique_lock<mutex> lock(mpMap->mMutexPointCreation);
    mnId=nNextId++;
}

void MapPoint::SetWorldPos(const cv::Mat &Pos)
{
    unique_lock<mutex> lock2(mGlobalMutex);
    unique_lock<mutex> lock(mMutexPos);
    Pos.copyTo(mWorldPos);

    if(mObejctID.status()) {
        mpMap->AddMapPointUpdateBuffer(this, "mWorldPos");
    }
}

cv::Mat MapPoint::GetWorldPos()
{
    unique_lock<mutex> lock(mMutexPos);

    return mWorldPos.clone();
}

cv::Mat MapPoint::GetNormal()
{
    unique_lock<mutex> lock(mMutexPos);
    return mNormalVector.clone();
}

KeyFrame* MapPoint::GetReferenceKeyFrame()
{
    unique_lock<mutex> lock(mMutexFeatures);
    return mpRefKF;
}

void MapPoint::AddObservation(KeyFrame* pKF, size_t idx)
{
    unique_lock<mutex> lock(mMutexFeatures);
    if(mObservations.count(pKF))
        return;
    mObservations[pKF]=idx;

    if(pKF->mvuRight[idx]>=0)
        nObs+=2;
    else
        nObs++;

    if(mObejctID.status()) {
        mpMap->AddMapPointUpdateBuffer(this, "mObservations");
        mpMap->AddMapPointUpdateBuffer(this, "nObs");
    }
}

void MapPoint::EraseObservation(KeyFrame* pKF)
{
    bool bBad=false;
    {
        unique_lock<mutex> lock(mMutexFeatures);
        if(mObservations.count(pKF))
        {
            int idx = mObservations[pKF];
            if(pKF->mvuRight[idx]>=0)
                nObs-=2;
            else
                nObs--;

            mObservations.erase(pKF);

            if(mpRefKF==pKF)
                mpRefKF=mObservations.begin()->first;

            // If only 2 observations or less, discard point
            if(nObs<=2)
                bBad=true;

            if(mObejctID.status()) {
                mpMap->AddMapPointUpdateBuffer(this, "mObservations");
                mpMap->AddMapPointUpdateBuffer(this, "nObs");
            }
        }
    }

    if(bBad)
        SetBadFlag();
}

map<KeyFrame*, size_t> MapPoint::GetObservations()
{
    unique_lock<mutex> lock(mMutexFeatures);
    return mObservations;
}

int MapPoint::Observations()
{
    unique_lock<mutex> lock(mMutexFeatures);
    return nObs;
}

void MapPoint::SetBadFlag()
{
    map<KeyFrame*,size_t> obs;
    {
        unique_lock<mutex> lock1(mMutexFeatures);
        unique_lock<mutex> lock2(mMutexPos);
        mbBad=true;
        obs = mObservations;
        mObservations.clear();
    }
    for(map<KeyFrame*,size_t>::iterator mit=obs.begin(), mend=obs.end(); mit!=mend; mit++)
    {
        KeyFrame* pKF = mit->first;
        pKF->EraseMapPointMatch(mit->second);
    }

    //! 直接删除点时其他变量就不用更新了
    mpMap->EraseMapPoint(this);
}

MapPoint* MapPoint::GetReplaced()
{
    unique_lock<mutex> lock1(mMutexFeatures);
    unique_lock<mutex> lock2(mMutexPos);
    return mpReplaced;
}

void MapPoint::Replace(MapPoint* pMP)
{
    if(pMP->mnId==this->mnId)
        return;

    int nvisible, nfound;
    map<KeyFrame*,size_t> obs;
    {
        unique_lock<mutex> lock1(mMutexFeatures);
        unique_lock<mutex> lock2(mMutexPos);
        obs=mObservations;
        mObservations.clear();
        mbBad=true;
        nvisible = mnVisible;
        nfound = mnFound;
        mpReplaced = pMP;
    }

    for(map<KeyFrame*,size_t>::iterator mit=obs.begin(), mend=obs.end(); mit!=mend; mit++)
    {
        // Replace measurement in keyframe
        KeyFrame* pKF = mit->first;

        if(!pMP->IsInKeyFrame(pKF))
        {
            pKF->ReplaceMapPointMatch(mit->second, pMP);
            pMP->AddObservation(pKF,mit->second);
        }
        else
        {
            pKF->EraseMapPointMatch(mit->second);
        }
    }
    pMP->IncreaseFound(nfound);
    pMP->IncreaseVisible(nvisible);
    pMP->ComputeDistinctiveDescriptors();

    //! 直接删除点时其他变量就不用更新了
    mpMap->EraseMapPoint(this);

}

bool MapPoint::isBad()
{
    unique_lock<mutex> lock(mMutexFeatures);
    unique_lock<mutex> lock2(mMutexPos);
    return mbBad;
}

void MapPoint::IncreaseVisible(int n)
{
    unique_lock<mutex> lock(mMutexFeatures);
    mnVisible+=n;

    if(mObejctID.status()) {
        mpMap->AddMapPointUpdateBuffer(this, "mnVisible");
    }
}

void MapPoint::IncreaseFound(int n)
{
    unique_lock<mutex> lock(mMutexFeatures);
    mnFound+=n;

    if(mObejctID.status()) {
        mpMap->AddMapPointUpdateBuffer(this, "mnFound");
    }
}

float MapPoint::GetFoundRatio()
{
    unique_lock<mutex> lock(mMutexFeatures);
    return static_cast<float>(mnFound)/mnVisible;
}

void MapPoint::ComputeDistinctiveDescriptors()
{
    // Retrieve all observed descriptors
    vector<cv::Mat> vDescriptors;

    map<KeyFrame*,size_t> observations;

    {
        unique_lock<mutex> lock1(mMutexFeatures);
        if(mbBad)
            return;
        observations=mObservations;
    }

    if(observations.empty())
        return;

    vDescriptors.reserve(observations.size());

    for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++)
    {
        KeyFrame* pKF = mit->first;

        if(!pKF->isBad())
            vDescriptors.push_back(pKF->mDescriptors.row(mit->second));
    }

    if(vDescriptors.empty())
        return;

    // Compute distances between them
    const size_t N = vDescriptors.size();

    float Distances[N][N];
    for(size_t i=0;i<N;i++)
    {
        Distances[i][i]=0;
        for(size_t j=i+1;j<N;j++)
        {
            int distij = ORBmatcher::DescriptorDistance(vDescriptors[i],vDescriptors[j]);
            Distances[i][j]=distij;
            Distances[j][i]=distij;
        }
    }

    // Take the descriptor with least median distance to the rest
    int BestMedian = INT_MAX;
    int BestIdx = 0;
    for(size_t i=0;i<N;i++)
    {
        vector<int> vDists(Distances[i],Distances[i]+N);
        sort(vDists.begin(),vDists.end());
        int median = vDists[0.5*(N-1)];

        if(median<BestMedian)
        {
            BestMedian = median;
            BestIdx = i;
        }
    }

    {
        unique_lock<mutex> lock(mMutexFeatures);
        mDescriptor = vDescriptors[BestIdx].clone();

        if(mObejctID.status()) {
            mpMap->AddMapPointUpdateBuffer(this, "mDescriptor");
        }
    }
}

cv::Mat MapPoint::GetDescriptor()
{
    unique_lock<mutex> lock(mMutexFeatures);
    return mDescriptor.clone();
}

int MapPoint::GetIndexInKeyFrame(KeyFrame *pKF)
{
    unique_lock<mutex> lock(mMutexFeatures);
    if(mObservations.count(pKF))
        return mObservations[pKF];
    else
        return -1;
}

bool MapPoint::IsInKeyFrame(KeyFrame *pKF)
{
    unique_lock<mutex> lock(mMutexFeatures);
    return (mObservations.count(pKF));
}

void MapPoint::UpdateNormalAndDepth()
{
    map<KeyFrame*,size_t> observations;
    KeyFrame* pRefKF;
    cv::Mat Pos;
    {
        unique_lock<mutex> lock1(mMutexFeatures);
        unique_lock<mutex> lock2(mMutexPos);
        if(mbBad)
            return;
        observations=mObservations;
        pRefKF=mpRefKF;
        Pos = mWorldPos.clone();
    }

    if(observations.empty())
        return;

    cv::Mat normal = cv::Mat::zeros(3,1,CV_32F);
    int n=0;
    for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++)
    {
        KeyFrame* pKF = mit->first;
        cv::Mat Owi = pKF->GetCameraCenter();
        cv::Mat normali = mWorldPos - Owi;
        normal = normal + normali/cv::norm(normali);
        n++;
    }

    cv::Mat PC = Pos - pRefKF->GetCameraCenter();
    const float dist = cv::norm(PC);
    const int level = pRefKF->mvKeysUn[observations[pRefKF]].octave;
    const float levelScaleFactor =  pRefKF->mvScaleFactors[level];
    const int nLevels = pRefKF->mnScaleLevels;

    {
        unique_lock<mutex> lock3(mMutexPos);
        mfMaxDistance = dist*levelScaleFactor;
        mfMinDistance = mfMaxDistance/pRefKF->mvScaleFactors[nLevels-1];
        mNormalVector = normal/n;

        if(mObejctID.status())
        {
            mpMap->AddMapPointUpdateBuffer(this, "mfMaxDistance");
            mpMap->AddMapPointUpdateBuffer(this, "mfMinDistance");
            mpMap->AddMapPointUpdateBuffer(this, "mNormalVector");
        }
    }
}

float MapPoint::GetMinDistanceInvariance()
{
    unique_lock<mutex> lock(mMutexPos);
    return 0.8f*mfMinDistance;
}

float MapPoint::GetMaxDistanceInvariance()
{
    unique_lock<mutex> lock(mMutexPos);
    return 1.2f*mfMaxDistance;
}

int MapPoint::PredictScale(const float &currentDist, KeyFrame* pKF)
{
    float ratio;
    {
        unique_lock<mutex> lock(mMutexPos);
        ratio = mfMaxDistance/currentDist;
    }

    int nScale = ceil(log(ratio)/pKF->mfLogScaleFactor);
    if(nScale<0)
        nScale = 0;
    else if(nScale>=pKF->mnScaleLevels)
        nScale = pKF->mnScaleLevels-1;

    return nScale;
}

int MapPoint::PredictScale(const float &currentDist, Frame* pF)
{
    float ratio;
    {
        unique_lock<mutex> lock(mMutexPos);
        ratio = mfMaxDistance/currentDist;
    }

    int nScale = ceil(log(ratio)/pF->mfLogScaleFactor);
    if(nScale<0)
        nScale = 0;
    else if(nScale>=pF->mnScaleLevels)
        nScale = pF->mnScaleLevels-1;

    return nScale;
}

const bsoncxx::types::b_oid MapPoint::WriteToDataBase()
{
    bsoncxx::builder::stream::document doc;
    doc << "mnId" << bsoncxx::types::b_int64{static_cast<int64_t>(mnId)}
          << "mnFirstKFid" << mnFirstKFid
          << "mnFirstFrame" << mnFirstFrame
          << "nObs" << nObs;

    if(!mPosGBA.empty())
        doc << MongoIO::types::b_mat{"mPosGBA", mPosGBA};
    else
        doc << "mPosGBA" << bsoncxx::types::b_null{};

    doc << MongoIO::types::b_mat{"mWorldPos", mWorldPos};

    std::vector<std::pair<bsoncxx::types::b_oid, int64_t> > Observations;
    for_each(mObservations.begin(), mObservations.end(), [&](std::pair<KeyFrame*,size_t> val){
        if(!val.first->MongoID().status())
            std::cerr << "Error in writing MapPoint::mObservations!!! The KeyFrame " << val.first->mnId << " is not in the database!!!" << std::endl;
        Observations.push_back(std::pair<bsoncxx::types::b_oid, int64_t>(val.first->MongoID().oid(), val.second));
    });

    doc << MongoIO::types::b_vector<std::pair<bsoncxx::types::b_oid, int64_t> >{"mObservations", Observations};

    doc << MongoIO::types::b_mat{"mNormalVector", mNormalVector}
        << MongoIO::types::b_mat{"mDescriptor", mDescriptor};

    doc << "mpRefKF" << mpRefKF->MongoID().oid()
        << "mnVisible" << mnVisible
        << "mnFound" << mnFound
        << "mbBad" << mbBad;

    if(mpReplaced)
        doc << "mpReplaced" << mpReplaced->MongoID().oid();
    else
        doc << "mpReplaced" << bsoncxx::types::b_oid{};

    doc << "mfMinDistance" << mfMinDistance
        << "mfMaxDistance" << mfMaxDistance;

    //! Write to DataBase && Get ObejctID
    {
        unique_lock<mutex> lock1(mMutexFeatures);
        unique_lock<mutex> lock2(mMutexPos);
        bsoncxx::types::b_oid oid = mpMap->mpMongoIO->WriteToDataBase(Map::sDatabase, Map::sCollectionMP, doc.view());
        mObejctID = MongoIO::ID(oid);
    }

    return mObejctID.oid();
}

bool MapPoint::EraseFromDataBase()
{
    const bsoncxx::types::b_oid oid = mObejctID.oid();
    mObejctID = MongoIO::ID();

    return mpMap->mpMongoIO->EraseFromDataBase(Map::sDatabase, Map::sCollectionMP, oid);
}

bool MapPoint::UpdateToDataBase(const std::set<std::string> &paras)
{
    if(!mObejctID.status()) {
        std::cerr << " Unvaluable MapPoint: " << mnId << ", UpdateToDataBase rejected"  << std::endl;
        return false;
    }

    bsoncxx::builder::stream::document update_builder{};

    for_each(paras.begin(), paras.end(), [&](const std::string para)
    {
        if("nObs" == para)
        {
            update_builder << "nObs" << nObs;
        }
        else if("mWorldPos" == para) {
            update_builder << MongoIO::types::b_mat{"mWorldPos", mWorldPos};
        }
        else if("mObservations" == para)
        {
            std::vector<std::pair<bsoncxx::types::b_oid, int64_t> > Observations;
            for_each(mObservations.begin(), mObservations.end(), [&](std::pair<KeyFrame*,size_t> val){
              if(!val.first->MongoID().status())
                  std::cerr << "Error in writing MapPoint::mObservations!!! The KeyFrame " << val.first->mnId << " is not in the database!!!" << std::endl;
              Observations.push_back(std::pair<bsoncxx::types::b_oid, int64_t>(val.first->MongoID().oid(), val.second));
            });

            update_builder << MongoIO::types::b_vector<std::pair<bsoncxx::types::b_oid, int64_t> >{"mObservations", Observations};
        }
        else if("mNormalVector" == para)
        {
            update_builder << MongoIO::types::b_mat{"mNormalVector", mNormalVector};
        }
        else if("mDescriptor" == para)
        {
            update_builder << MongoIO::types::b_mat{"mDescriptor", mDescriptor};
        }
        else if("mpRefKF" == para)
        {
            update_builder << "mpRefKF" << mpRefKF->MongoID().oid();
        }
        else if("mnVisible" == para)
        {
            update_builder << "mnVisible" << mnVisible;
        }
        else if("mnFound" == para)
        {
            update_builder << "mnFound" << mnFound;
        }
        else if("mbBad" == para)
        {
            update_builder << "mbBad" << mbBad;
        }
        else if("mpReplaced" == para)
        {
            if(mpReplaced) {
                update_builder << "mpReplaced" << mpReplaced->MongoID().oid();
            }
            else {
                update_builder << "mpReplaced" << bsoncxx::types::b_oid{};
            }
        }
        else if("mfMinDistance" == para)
        {
            update_builder << "mfMinDistance" << mfMinDistance;
        }
        else if("mfMaxDistance" == para)
        {
            update_builder << "mfMaxDistance" << mfMaxDistance;
        }
        else
        {
            std::cerr << "MapPoint::UpdateToDataBase Unknow parameter: " << para << std::endl;
            return false;
        }
    });

    mpMap->mpMongoIO->UpdateToDataBase(Map::sDatabase, Map::sCollectionMP, mObejctID.oid(), update_builder.view());

    return true;
}

bool MapPoint::UpdateFromDataBase(const std::set<std::string> &paras)
{
    if(!mObejctID.status())
    {
        std::cerr << " Unvaluable MapPoint: " << mnId << ", UpdateFromDataBase rejected"  << std::endl;
        return false;
    }

    mongocxx::options::find opts{};
    bsoncxx::builder::stream::document opts_builder{};
    for_each(paras.begin(), paras.end(), [&](const std::string para){
        opts_builder<< para << 1;
    });
    opts.projection(opts_builder.view());

    bsoncxx::stdx::optional<bsoncxx::document::value> result;
    mpMap->mpMongoIO->FindFromDataBase(Map::sDatabase, Map::sCollectionMP, mObejctID.oid(), opts, result);
    if(!result)
    {
        std::cerr << " It can not happen!!! MapPoint::UpdateFromDataBase empty result, MapPoint: " << mnId << std::endl;
        return false;
    }
    bsoncxx::document::view view{result.value().view()};
//    std::cout << "find: " << bsoncxx::to_json(view) << std::endl;

    for_each(paras.begin(), paras.end(), [&](const std::string para) {
        if("nObs" == para)
        {
          nObs = view["nObs"].get_int32();
        }
        else if("mWorldPos" == para) {
          mWorldPos = MongoIO::types::b_mat::from(view["mWorldPos"]);
        }
        else if("mObservations" == para)
        {
          MapPoint::GetFromDatabase(mObservations, mpMap, view["mObservations"]);
        }
        else if("mNormalVector" == para)
        {
          mNormalVector = MongoIO::types::b_mat::from(view["mNormalVector"]);
        }
        else if("mDescriptor" == para)
        {
          mDescriptor = MongoIO::types::b_mat::from(view["mDescriptor"]);
        }
        else if("mpRefKF" == para)
        {
          bsoncxx::types::b_oid pRefKFID = view["mpRefKF"].get_oid();
          mpRefKF = mpMap->GetDatabaseKeyFrame(pRefKFID);
        }
        else if("mnVisible" == para)
        {
          mnVisible = view["mnVisible"].get_int32();
        }
        else if("mnFound" == para)
        {
          mnFound = view["mnFound"].get_int32();
        }
        else if("mbBad" == para)
        {
          mbBad = view["mbBad"].get_bool();
        }
        else if("mpReplaced" == para)
        {
          bsoncxx::types::b_oid pReplacedID = view["mpReplaced"].get_oid();
          mpReplaced = mpMap->GetDatabaseMapPoint(pReplacedID);
        }
        else if("mfMinDistance" == para)
        {
          mfMinDistance = view["mfMinDistance"].get_double();
        }
        else if("mfMaxDistance" == para)
        {
          mfMaxDistance = view["mfMaxDistance"].get_double();
        }
        else
        {
          std::cerr << "MapPoint::UpdateFromDataBase Unknow parameter: " << para << std::endl;
          return false;
        }
    });

    return true;
}

void MapPoint::GetFromDatabase(std::map<KeyFrame *, size_t> &mpKFn, Map *map, const bsoncxx::document::element &elem)
{
    std::vector<std::pair<bsoncxx::types::b_oid, int64_t> > Observations = MongoIO::types::b_vector<std::pair<bsoncxx::types::b_oid, int64_t> >::from(elem);
    for_each(Observations.begin(), Observations.end(), [&](std::pair<bsoncxx::types::b_oid, int64_t> val){
        KeyFrame* pKF = map->GetDatabaseKeyFrame(val.first);
        if(pKF)
        {
            mpKFn.insert(std::pair<KeyFrame*, size_t>(pKF, val.second));
        }
        else
        {
        //    std::cerr << "\nError!!! MapPoint::GetFromDatabase" << elem.key().to_string()
        //              << " Can not find the oid[" << val.first.value.to_string() << "]" << std::endl;
        }
    });
}

MapPoint::MapPoint(const bsoncxx::document::view &view, const MongoIO::ID &id, Map *pMap) :
    mnTrackReferenceForFrame(0), mnLastFrameSeen(0), mnBALocalForKF(0), mnFuseCandidateForKF(0),
    mnLoopPointForKF(0), mnCorrectedByKF(0), mnCorrectedReference(0), mnBAGlobalForKF(0),
    mObejctID(id), mpMap(pMap)
{

    mnId = view["mnId"].get_int64();
    mnFirstKFid = view["mnFirstKFid"].get_int64();
    mnFirstFrame = view["mnFirstFrame"].get_int64();
    nObs = view["nObs"].get_int32();

    if(view["mPosGBA"] && view["mPosGBA"].type() == bsoncxx::type::k_array)
        mPosGBA = MongoIO::types::b_mat::from(view["mPosGBA"]);

    mWorldPos = MongoIO::types::b_mat::from(view["mWorldPos"]);

    MapPoint::GetFromDatabase(mObservations, mpMap, view["mObservations"]);

    mNormalVector = MongoIO::types::b_mat::from(view["mNormalVector"]);
    mDescriptor = MongoIO::types::b_mat::from(view["mDescriptor"]);

    bsoncxx::types::b_oid pRefKFID = view["mpRefKF"].get_oid();
    mpRefKF = mpMap->GetDatabaseKeyFrame(pRefKFID);

    mnVisible = view["mnVisible"].get_int32();
    mnFound = view["mnFound"].get_int32();

    mbBad = view["mbBad"].get_bool();

    bsoncxx::types::b_oid pReplacedID = view["mpReplaced"].get_oid();
    mpReplaced = mpMap->GetDatabaseMapPoint(pReplacedID);

    mfMinDistance = view["mfMinDistance"].get_double();
    mfMaxDistance = view["mfMaxDistance"].get_double();
}

} //namespace ORB_SLAM
